﻿import { _decorator, Component, Node, js, System, Label, cclegacy, ParticleSystem2D, UITransform, EditBox } from 'cc';
import * as c from 'cc';
import { HttpUtils } from '../utils/HttpUtils';
import { GlobalVar } from '../common/GlobalVar';

const { ccclass, property } = _decorator;



@ccclass('CodeReoladTool')
export class CodeReoladTool {
    static modCache = new Map<string, Object>();
    static lastTime = 0;
    static global = "";
    static funcNameCode = ""
    static bodyCode = ""


    static getArgsString(...args) {
        if (args.length == 0)
            return "";
        let param = ""
        for (let i = 0; i < args.length;i++) {
            param += args[i]
            if (i != args.length - 1) {
                param+=","
            }
        }
        return param
    }
    
                

    static reloadFuncCode(cls, code, funcName, isAsync, isStatic, ...args) {
        //console.log("重载方法", funcName, args, code)

        code = this.getGlobal() + code
      
        let param = this.getArgsString(...args);
        let functionCode = ""
        if (isAsync && isStatic) {
            functionCode = `
             class ${cls.name}{
                static async ${funcName}(${param}) {
                    ${code}
                }
             }
             return ${cls.name}.${funcName};
            `;

        }
        else if (isAsync && !isStatic) {
            functionCode = `
                async function ${funcName}(${param}) {
                    ${code}
                };
                return ${funcName};
            `;

        }
        else if (!isAsync && isStatic) {
            functionCode = `
            class ${cls.name}{
                static ${funcName}(${param}) {
                    ${code}
                }

            }
             return ${cls.name}.${funcName};
            `;


        }
        else {
            functionCode = `
                function ${funcName}(${param}) {
                    ${code}
                };
                return ${funcName};
            `;

        }

        //console.log("完整函数", functionCode)

        const createAsyncFunction = new Function(functionCode);

        // 获取实际的 async 函数
        const asyncFunction = createAsyncFunction();
        cls.prototype[funcName] = asyncFunction
    }


    static checkIsParallelBars(line: string, i: number) {
        if (line[i] != "/")
            return false;

        if (i + 1 < line.length) {
            if (line[i + 1] == "/")
                return true;
        }
        return false;
    }

    static checkIsNote(line: string, i: number) {
        if (line[i] != "/")
            return false;

        if (i + 1 < line.length) {
            if (line[i + 1] == "*")
                return true;
        }
        return false;
    }

    static checkIsNoteEnd(line: string, i: number) {
        if (line[i] != "*")
            return false;

        if (i + 1 < line.length) {
            if (line[i + 1] == "/")
                return true;
        }
        return false;
    }

    static isAppendChar(isBody,isNeedMatch, keyList,char) {
        //拼接文本
        if (isBody) {
            this.bodyCode += char
        } else {
            if (!isNeedMatch) {
                let lastKey = keyList[keyList.length - 1];
                if (lastKey == "/*" || lastKey == "//") {
                    return false
                }
            }
            this.funcNameCode += char
           
        }
        return true
    }


    static reverseString(str) {
        let reversed = '';
        for (let i = str.length - 1; i >= 0; i--) {
            reversed += str[i];
        }
        return reversed;
    }

    static getFuncData(funcNameCode: string) {
       
        let codeList = funcNameCode.split("\r\n")
        let line = ""
        for (let i = codeList.length - 1; i >= 0; i--) {
            line = codeList[i];
            if (line.indexOf(")")>0) {
                break;
            }
        }
        let isAsync = false;
        let isStatic = false;

        if (line.indexOf("async")>0) {
            isAsync = true;
        }
        if (line.indexOf("static")>0) {
            isStatic = true;
        }
        let args = []//顺序是反的
        let isStart = false;
        let argsCode = ""
        for (let i = line.length - 1; i >= 0; i--) {
            if (line[i] == ")") {
                isStart = true;
                continue
            }
            if (line[i] == "(") {
                args.push(this.reverseString(argsCode))
                break;
            }
            if (line[i] == ",") {
                args.push(this.reverseString(argsCode))
                argsCode = "";
                continue
            }

            argsCode += line[i]
        }


        let params = []
        for (let i = args.length - 1; i >= 0; i--) {
            let arg = args[i]
            let index = arg.indexOf("?")
            if (index<=0)
                index = arg.indexOf(":")
            if (index > 0)
                arg = arg.substring(0, index);
            arg = arg.replace(" ", "")
            params.push(arg)
        }
        let funcName = ""
        isStart = false;
        for (let i = line.length - 1; i >= 0; i--) {
            if (line[i] == "(") {
                isStart = true;
                continue
            }
            if (!isStart)
                continue
            if (line[i] == " ")
                break;
            funcName += line[i]
        }
        funcName = this.reverseString(funcName)
      
        return {
            funcName: funcName,
            params: params,
            isAsync: isAsync,
            isStatic: isStatic,
        }

    }

    static reloadClsCode(code: string)
    {
        let index = code.indexOf("@ccclass(");
        code = code.substring(index);
        code = code.substring(code.indexOf("{")+1, code.lastIndexOf("}")-1);
        let codeList = code.split("\r\n")
        let keyList = []
        
        this.funcNameCode = ""
        this.bodyCode = ""
        let isBody = false;
        let isNeedMatch = true;

        let methods = []
        for (let line of codeList) {

            if (!isNeedMatch) {
                let lastKey = keyList[keyList.length - 1];
                if (lastKey == "//") {
                    keyList.pop()
                    isNeedMatch = true;
                }
            }


            for (let i = 0; i < line.length; i++) {
                let isGetNotMatchKey = false;//匹配到引号什么的 要等下一个引号出现才结束
                if (this.checkIsNote(line, i) || line[i] == '"' || this.checkIsParallelBars(line, i) || line[i] == "'" || line[i] == "`") {
                    if (isNeedMatch) {//不在注释、字符串什么的里面 才需要匹配
                        if (this.checkIsParallelBars(line, i)) {
                            keyList.push("//")
                            if (isBody)
                                this.isAppendChar(isBody, isNeedMatch, keyList, line[i])
                            i++;
                        } else if (this.checkIsNote(line, i)) {
                            keyList.push("/*")
                            if (isBody)
                                this.isAppendChar(isBody, isNeedMatch, keyList, line[i])
                            i++;
                        }
                        else {
                            keyList.push(line[i])
                        }
                        isGetNotMatchKey = true;
                        isNeedMatch = false;//都是注释什么的 不需要匹配
                    }

                } 

                if (isNeedMatch) {
                    if (line[i] == "{") {
                        keyList.push(line[i])
                        isBody = true;
                        //console.log("AAAAAAAA", keyList, bodyCode)
                        if (keyList.length == 1)
                            continue;
                    }
                    else if (line[i] == "}") {
                        keyList.pop()
                       // console.log(keyList)
                        if (keyList.length == 0) {
                            isBody = false;
                            let data = this.getFuncData(this.funcNameCode)
                            methods.push({
                                funcName: data.funcName,
                                params: data.params,
                                isAsync: data.isAsync,
                                isStatic: data.isStatic,
                                //funcNameCode: this.funcNameCode,
                                bodyCode: this.bodyCode,

                            })
                            this.bodyCode = "";
                            this.funcNameCode = "";
                            continue
                        }
                            
                    }
                } else {
                    //检测注释什么的是否结束
                    let lastKey = keyList[keyList.length - 1];
                    if (lastKey == "/*" && this.checkIsNoteEnd(line,i)) {
                        keyList.pop()
                        isNeedMatch = true;
                    } else if (lastKey == '"' && line[i] == '"' && !isGetNotMatchKey) {
                        keyList.pop()
                        isNeedMatch = true;
                    } else if (lastKey == "'" && line[i] == "'" && !isGetNotMatchKey) {
                        keyList.pop()
                        isNeedMatch = true;
                    } else if (lastKey == "`" && line[i] == "`" && !isGetNotMatchKey) {
                        keyList.pop()
                        isNeedMatch = true;
                    }
                    
                }

                if (!this.isAppendChar(isBody, isNeedMatch, keyList, line[i]))
                    continue
            }
            if (!this.isAppendChar(isBody, isNeedMatch, keyList, "\r\n"))
                continue

        }
        return methods

        // 打印结果
        //methods.forEach(method => {
        //    console.log(`函数名: ${method.funcName}`);
        //    console.log(`参数: ${method.params}`);
        //    console.log(`是否async: ${method.isAsyc}`);
        //    console.log(`是否static: ${method.isStatic}`);
        //    console.log(`内容: ${method.bodyCode}`);
        //});
    }

    static reload() {
        this.reloadFileList()
    }

    static getClsName(url: string) {
        url = url.replace("/","\\")
        let fileNameList = url.split("\\")
        let fileName = fileNameList[fileNameList.length - 1]
        return fileName.replace(".txt", "")
    }

    static async reloadFileList() {
        let fileStr = await HttpUtils.get("http://localhost:7456/assets/internal/import/reloadCode/file.json", false)

        let file = JSON.parse(fileStr)
        let fileList = Object.keys(file)
        for (let filePath of fileList) {
            let time = file[filePath]
            if (time < this.lastTime)
                continue

            let url = "http://localhost:7456/assets/internal/import/reloadCode/" + filePath
            let clsName = this.getClsName(url)
            let fileCode = await HttpUtils.get(url, false)
            console.log("重载=", clsName)
            let methods = this.reloadClsCode(fileCode)
            let cls = js.getClassByName(clsName)
            for (let method of methods) {
                try {
                    if (method.params.length == 0) {
                        this.reloadFuncCode(cls, method.bodyCode, method.funcName, method.isAsync, method.isStatic)
                    } else {
                        this.reloadFuncCode(cls, method.bodyCode, method.funcName, method.isAsync, method.isStatic, ...method.params)
                    }
                } catch (e) {
                    console.error(e)
                }

             
            }

        }

        this.lastTime = Date.parse(new Date());
    }

    static async init() {
        if (!GlobalVar.isTest)
            return;
        let r = Object.getOwnPropertySymbols(window.System);
        let obj = window.System[r[0]]
        let keyList = Object.keys(obj)

        for (let i = 0; i < keyList.length; i++) {
            let mod = obj[keyList[i]]
            let keys = Object.keys(mod.C)
            for (let name of keys) {
                let cls = js.getClassByName(name)
                if (cls != null) {
                    this.modCache.set(name, cls);
                }
            }
        }

        obj = c
        keyList = Object.keys(obj)
        for (let i = 0; i < keyList.length; i++) {
            let cls = obj[keyList[i]]
            this.modCache.set(keyList[i], cls);

        }

        window["reload"] = this.modCache

        for (let mod of window["reload"].keys()) {
            this.global += "var " + mod + "= window['reload'].get('" + mod + "');\n"
        }
        this.lastTime = Date.parse(new Date());
    }

    static getGlobal() {
        return this.global;
    }

}


